#include <time.h>
#include <stdio.h>
#include <assert.h>

#include "controller.h"
#include "packet.h"

typedef unsigned char byte;

typedef struct
		{
	  		byte sign_;
	  		byte rtc_hour_;
	 		byte rtc_min_;
	  		byte rtc_sec_;
	  		byte rtc_day_;
	  		byte rtc_month_;
	  		byte rtc_year_;
	  		byte rtc_day_of_week_;
	
	  		byte flash_status_;
	  		byte job_mode_;
	
	  		byte current_program_;
	  		byte current_phase_;
	
	  		byte fault_type_;
	  		byte fault_red_;
	  		byte fault_yellow_;
	  		byte fault_green_;

	  		byte no_programm_;
	  		byte phase_time_;
 
	  		char reserv_[9];
	
	} status_packet_t;


const unsigned char GET_STATUS = 0x20;
const unsigned char STATUS_PACKET = 0x20;

const unsigned char SYNC_TIME = 0x10;					// 17
const unsigned char CONTROLLER_GSM_TU = 0x17;	 		// 23
const unsigned char CONTROLLER_START_PROG_NUM = 0x12;   // 18
const unsigned char CONTROLLER_WRITE_PROG = 0x11;	// 17


#define TOBCD(x)  (((x) / 10 << 4) | ((x) % 10))

int build_status_packet(controller_t *_cont, status_packet_t *_status, struct tm **_tm)
{
	assert((_cont != NULL) && (_status !=NULL));
	
	memset(_status, 0, sizeof(status_packet_t));

	_status->sign_ = STATUS_PACKET;

	time_t tim = time(NULL);
		
	if (_cont->time_error_ > 0)
	{
		tim -= 900;
	}

	*_tm = localtime(&tim);

  	_status->rtc_hour_ = TOBCD((*_tm)->tm_hour);
 	_status->rtc_min_ = TOBCD((*_tm)->tm_min);
  	_status->rtc_sec_ = TOBCD((*_tm)->tm_sec);
  	_status->rtc_day_ = TOBCD((*_tm)->tm_mday);
  	_status->rtc_month_ = TOBCD((*_tm)->tm_mon + 1);
  	_status->rtc_year_ = TOBCD((*_tm)->tm_year - 100);
  	_status->rtc_day_of_week_  = TOBCD( (((*_tm)->tm_wday - 2) < 0) ? 6 : ((*_tm)->tm_wday - 2));

  	if (_cont->last_phase_time_ == 0)
  	{
  		_cont->current_phase_ = 0;
  		_cont->last_phase_time_ = tim;
  	}
  	else if ((tim - _cont->last_phase_time_)  >= _cont->phase_delay_)
  	{
  		_cont->current_phase_ = (_cont->current_phase_ == 8) ? 0 : (_cont->current_phase_ + 1 );
  		_cont->last_phase_time_ = tim;
  	}

  	_status->current_phase_ = _cont->current_phase_;
  	_status->current_program_ = _cont->current_prog_;

  	return 1;
}

#define CHUNK(a, b) (((b << 8) & 0xff00) | (a & 0xff))

int controller_exec_command(controller_t *_cont, const unsigned char *_in_packet, size_t _in_packet_len, char *_out_buffer, size_t _out_buffer_len, size_t *_real_len)
{
	status_packet_t status;
	struct tm *tm1;

	if ((_in_packet_len == 1) && (_in_packet[0] == GET_STATUS))
	{

		build_status_packet(_cont, &status, &tm1);

	  	printf(">>> Return status:num=%d, time='%02d.%02d.%02d %02d:%02d:%02d %d', phase=%d\n", _cont->controller_num_, tm1->tm_mday, tm1->tm_mon + 1, tm1->tm_year - 100, tm1->tm_hour, tm1->tm_min,  tm1->tm_sec, ((tm1->tm_wday - 1) < 0) ? 6 : (tm1->tm_wday - 1), _cont->current_phase_);

	}
	else if ((_in_packet_len == 8) && (_in_packet[0] == SYNC_TIME))
	{

		build_status_packet(_cont, &status, &tm1);

	  	_cont->time_error_ = 0;

	  	printf(">>> Sync time:num=%d, time='%02d.%02d.%02d %02d:%02d:%02d %d', phase=%d\n", _cont->controller_num_, tm1->tm_mday, tm1->tm_mon + 1, tm1->tm_year - 100, tm1->tm_hour, tm1->tm_min,  tm1->tm_sec, ((tm1->tm_wday - 1) < 0) ? 6 : (tm1->tm_wday - 1), _cont->current_phase_);

	}
	else if ((_in_packet_len == 2) && (_in_packet[0] == CONTROLLER_GSM_TU))
	{
	
		int tu = _in_packet[1];

		_cont->current_phase_ = tu;

		build_status_packet(_cont, &status, &tm1);

	  	printf(">>> Set phase:num=%d,TU=%d, time='%02d.%02d.%02d %02d:%02d:%02d %d', phase=%d\n", _cont->controller_num_, tu, tm1->tm_mday, tm1->tm_mon + 1, tm1->tm_year - 100, tm1->tm_hour, tm1->tm_min,  tm1->tm_sec, ((tm1->tm_wday - 1) < 0) ? 6 : (tm1->tm_wday - 1), _cont->current_phase_);

	}
	else if ((_in_packet_len == 2) && (_in_packet[0] == CONTROLLER_START_PROG_NUM))
	{
	
		int prog = _in_packet[1];

		_cont->current_prog_ = prog;

		build_status_packet(_cont, &status, &tm1);

	  	printf(">>> Set program:num=%d,program=%d, time='%02d.%02d.%02d %02d:%02d:%02d %d', phase=%d\n", _cont->controller_num_, prog, tm1->tm_mday, tm1->tm_mon + 1, tm1->tm_year - 100, tm1->tm_hour, tm1->tm_min,  tm1->tm_sec, ((tm1->tm_wday - 1) < 0) ? 6 : (tm1->tm_wday - 1), _cont->current_phase_);

	} 
	else if ((_in_packet_len > 1) && (_in_packet[0] == CONTROLLER_WRITE_PROG))
	{
	
		int chunk = CHUNK(_in_packet[1], _in_packet[2]);
		
		printf(">>> Write prog: chunk=%d\n", chunk);
		
		unsigned char answer = 0x00;
		
		if (build_packet(_out_buffer, (const unsigned char*)&answer, sizeof(answer), _out_buffer_len) < 0)
		{
			return 0;
		}
		
		*_real_len =  sizeof(answer) + 4;
		
		return 1;

	}
	else
	{
		return 0;
	}

	if (build_packet(_out_buffer, (const unsigned char*)&status, sizeof(status_packet_t), _out_buffer_len) < 0)
	{
		return 0;
	}

	*_real_len =  sizeof(status_packet_t) + 4;

	return 1;
}
